﻿using System;
using System.Windows.Automation;
using System.Windows.Automation.Provider;

namespace AutomationFramework
{
    /// <summary>
    /// A basic implementation of the Fragment provider.
    /// This adds the concept of a sub-window element to the Simple provider,
    /// and so includes work to report element aspects that the system
    /// would usually get for free from a window handle, like position and runtime ID.
    /// </summary>
    [System.Runtime.InteropServices.ComVisible(true)]
    public abstract class FragmentProvider : ItemProvider, IRawElementProviderFragment
    {
        #region Protected Fields

        protected IRawElementProviderFragment parent;
        protected IRawElementProviderFragmentRoot fragmentRoot;

        #endregion

        #region Constructors
        public FragmentProvider(IRawElementProviderFragment parent, IRawElementProviderFragmentRoot fragmentRoot)
        {
            this.parent = parent;
            this.fragmentRoot = fragmentRoot;
        }
        #endregion

        #region Overridden Methods

        /// <summary>
        /// Return the first child of this fragment.
        /// </summary>
        /// <returns></returns>
        protected virtual IRawElementProviderFragment GetFirstChild()
        {
            return null;
        }

        /// <summary>
        /// Return the last child of this fragment.
        /// </summary>
        /// <returns></returns>
        protected virtual IRawElementProviderFragment GetLastChild()
        {
            return null;
        }

        /// <summary>
        /// Return the next sibling of this fragment.
        /// </summary>
        /// <returns></returns>
        protected virtual IRawElementProviderFragment GetNextSibling()
        {
            return null;
        }

        /// <summary>
        /// Return the previous sibling of this fragment.
        /// </summary>
        /// <returns></returns>
        protected virtual IRawElementProviderFragment GetPreviousSibling()
        {
            return null;
        }
        #endregion

        #region IRawElementProviderFragment Members

        /// <summary>
        /// Return a unique runtime ID to distinguish this from other elements.
        /// </summary>
        /// <returns></returns>
        public abstract int[] GetRuntimeId();

        /// <summary>
        /// Return the bounding rectangle of the fragment.
        /// </summary>
        public abstract System.Windows.Rect BoundingRectangle
        {
            get;
        }

        /// <summary>
        /// Return any fragment roots embedded within this fragment.
        /// </summary>
        /// <returns></returns>
        public virtual IRawElementProviderSimple[] GetEmbeddedFragmentRoots()
        {
            return null;
        }

        /// <summary>
        /// Set focus to this fragment, if it is keyboard focusable.
        /// </summary>
        public virtual void SetFocus()
        {
        }

        /// <summary>
        /// Return the fragment root: the fragment that is tied to the window handle itself.
        /// </summary>
        public IRawElementProviderFragmentRoot FragmentRoot
        {
            get { return this.fragmentRoot; }
        }

        /// <summary>
        /// Routing function for going to neighboring elements.  
        /// </summary>
        /// <param name="direction"></param>
        /// <returns></returns>
        public IRawElementProviderFragment Navigate(NavigateDirection direction)
        {
            switch (direction)
            {
                case NavigateDirection.Parent: return this.parent;
                case NavigateDirection.FirstChild: return GetFirstChild();
                case NavigateDirection.LastChild: return GetLastChild();
                case NavigateDirection.NextSibling: return GetNextSibling();
                case NavigateDirection.PreviousSibling: return GetPreviousSibling();
            }
            return null;
        }

        #endregion
    }
}
